package com.tangsm.spring.boot.validation.config.mvc;

import com.tangsm.spring.boot.validation.util.HttpServletUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;

/**
 * 自定义请求参数处理，防止流Body参数丢失，重写HttpServletRequestWrapper类包装的请求对象
 * <p>ps:</p>
 * <p>解决请求拦截器获取body参数请求放过后报错问题。</p>
 * <p>post请求参数在body中获取，request中的资源只能获取一次，进而要将body保存下来，重写HttpServletRequestWrapper类。</p>
 *
 * @author tangsm
 * @since 2021/12/27
 */
public class RequestWrapper extends HttpServletRequestWrapper {
    /**
     * 缓存下来的HTTP body
     */
    private final byte[] body;

    /**
     * 有参构造
     * @param request 当前的HTTP请求
     */
    public RequestWrapper(HttpServletRequest request) {
        super(request);
        body = HttpServletUtils.getBody(request);
    }

    /**
     * 重写getReader
     * @return 包含请求正文的BufferedReader
     */
    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    /**
     * 重新包装输入流
     * @return 数据的输入流
     */
    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public int read() {
                return bais.read();
            }

            /**
             * 下面的方法一般情况下不会被使用，如果你引入了一些需要使用ServletInputStream的外部组件，可以重点关注一下。
             * @return
             */
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }
}
